
#pragma once
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>

#include <netinet/in.h>
#include <arpa/inet.h>
#include <iostream>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
using namespace std;

#include "Log.hpp"
#include "ThreadPool.hpp"
using namespace ThreadPoolModule;
using namespace MyLogModule;

using handler_t = function<string(string& package)>;
using task_t = std::function<void()>;

const uint16_t g_port = 8080;
class tcpServer
{
private:
    int _socket;
    bool _isRunning;
    int _port;
    handler_t _handle;
    struct ThreadData
    {
        int sockfd;
        tcpServer* self;
    };
public:
    tcpServer(handler_t handle,int port = g_port)
        :_isRunning(false)
        ,_port(port)
        ,_handle(handle)
    {}
    ~tcpServer()
    {}
    void Init()
    {
        //1. 创建socket
        _socket = ::socket(AF_INET,SOCK_STREAM,0);
        if(_socket < 0)
        {
            LOG(LogGrade::ERROR) << "create socket fail";
            return;
        }
        LOG(LogGrade::NORMAL) << "create socket success,socket:" << _socket;
        //2 .绑定
            //2.1设置
        struct sockaddr_in local;
        memset(&local,0,sizeof(local));
        local.sin_family = AF_INET;
        local.sin_addr.s_addr = INADDR_ANY;
        local.sin_port = ::htons(g_port);

            //2.2绑定
        int n = ::bind(_socket,(sockaddr*)&local,sizeof(local));
        if(n < 0)
        {
            LOG(LogGrade::ERROR) << "bind socket fail";
            return;
        }
        LOG(LogGrade::NORMAL) << "bind socket success,socket:" << _socket;


        //3. 监听
        n = ::listen(_socket,4);
        if(n < 0)
        {
            LOG(LogGrade::ERROR) << "listen fail";
            return;
        }
        LOG(LogGrade::NORMAL) << "listen success";

    }
    void Start()
    {
        _isRunning = true;
        while(_isRunning)
        {
            struct sockaddr_in from;    //用来存放接受连接的客户端的地址信息
            socklen_t len = sizeof(from);
            //获取客户端的数据（sockfd） + 信息(accept 的参数获得)

            //_Socket正在监听的socket     （拉客的）
            //返回值是一个socket,即所接待的人的fd (接待的服务员)
            int fd = ::accept(_socket,(sockaddr*)&from,&len);
            if(fd < 0)
            {
                LOG(LogGrade::ERROR) << "accept fail";
                continue;
            }
            LOG(LogGrade::NORMAL) << "accept success,fd:" << fd;

            //version1，单执行流
            // HandleTask(fd);

            //version2,多进程
            // pid_t id = fork();
            // if(id == 0)
            // {
            //     //1. 子进程关闭不需要的文件描述符
            //     close(_socket);
            //     //为了避免父进程阻塞，子进程退出，让孙子进程处理任务
            //     if(fork() > 0)
            //         exit(0);
            //     //孙子进程-->孤儿进程-->1
            //     HandleTask(fd);
            //     exit(0);
            // }
            // //父进程关闭fd(它不关心这个文件描述符表了，已经继承给子进程处理了)
            // close(fd);
            // int rid = waitpid(id,nullptr,0);
            // if(rid < 0)
            // {
            //     LOG(LogGrade::ERROR) << "waitpid error";
            // }
            // LOG(LogGrade::NORMAL) << "waitpid success:" << rid;

            //version3,多线程
            pthread_t pid;
            // pthread_create(&pid,nullptr,HandleTask,fd); //这样参数无法传递
            ThreadData data;
            data.sockfd = fd;
            data.self = this;
            pthread_create(&pid,nullptr,ThreadEntry,&data);

            //version4，线程池版本
            // ThreadPool<task_t>::GetInstance()->Push([this,fd](){
            //     this->HandleTask(fd);
            // });
        }
        _isRunning = false;
    }

    //多线程使用
    static void* ThreadEntry(void* args)
    {
        pthread_detach(pthread_self()); //去关联
        ThreadData* data = (ThreadData*)args;
        data->self->HandleTask(data->sockfd);
        return nullptr;
    }

    void HandleTask(int fd)
    {
        LOG(LogGrade::NORMAL) << "HandlerRequest, sockfd is : " << fd;
        char buffer[2048];
        string package;
        while(true)
        {
            //从指定的fd中读取
            int n = ::recv(fd,buffer,sizeof(buffer),0);
            if(n > 0)
            {
                buffer[n] = 0;
                LOG(LogGrade::NORMAL) << buffer;
                package += buffer;
                // // string message = "echo# ";
                // // message += buffer;
                // //返回给发送者
                // write(fd,message.c_str(),message.size());

                string cmd_result = _handle(package);
                if(cmd_result.empty())  //报文不完整，继续读
                    continue;

                send(fd,cmd_result.c_str(),cmd_result.size(),0);    
            }
            else if(n == 0)
            {
                LOG(LogGrade::NORMAL) << "client quit,fd:" << fd;
                break;
            }
            else
                break;
        }
        close(fd);
    }
};